/**
 * Project name : sklay-core
 * File name : StaticResourceMappingManagerImpl.java
 * Package name : com.sklay.core.io
 * Date : 2013-11-27
 * Copyright : 2013 , sklay.COM All Rights Reserved
 * Author : 1988fuyu@163.com
 */
package com.hoperun.framework.io;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import sun.misc.BASE64Decoder;

import com.google.common.collect.Lists;
import com.hoperun.framework.io.image.CommonImage;
import com.hoperun.framework.models.FileInfo;

public class StaticResourceMappingManagerImpl implements
		StaticResourceMappingManager, ServletContextAware,
		ApplicationContextAware, InitializingBean {

	private final static Logger LOGGER = LoggerFactory
			.getLogger(StaticResourceMappingManagerImpl.class);

	private ServletContext servletContext;

	private ApplicationContext applicationContext;

	private static final String DEFAULT_UPLOAD_PATH = "/WEB-INF/upload";

	private int cacheSeconds = 31556926;

	private String uploadPath = DEFAULT_UPLOAD_PATH;

	private String downloadPath;

	private String workerOrderPath;

	private ResourceLoader resourceLoader = new DefaultResourceLoader();

	@Override
	public String getUploadPath() {
		return uploadPath;
	}

	@Override
	public String getDowloadRealPath() {

		Resource resource = resourceLoader.getResource(StringUtils
				.cleanPath(getUploadPath() + File.separator + downloadPath));
		try {
			if (!resource.exists()) {
				FileUtils.forceMkdir(resource.getFile());
			}
			return getUploadPath() + File.separator + downloadPath;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return getUploadPath() + File.separator + downloadPath;
		} catch (IOException e) {
			e.printStackTrace();
			return getUploadPath() + File.separator + downloadPath;
		}
	}

	@Override
	public List<String> uploadWorkOrderRealPath(String owner,
			List<String> imagesBase64) {
		List<String> list = Lists.newArrayList();

		String path = getUploadPath() + File.separator + workerOrderPath;
		if (!StringUtils.isEmpty(owner))
			path += File.separator + owner;
		Resource resource = resourceLoader.getResource(StringUtils
				.cleanPath(path));
		try {
			if (!resource.exists()) {
				FileUtils.forceMkdir(resource.getFile());
			}
			for (String imageBase64 : imagesBase64) {

				if (org.apache.commons.lang.StringUtils.isNotBlank(imageBase64)) {
					String name = (new Date()).getTime() + ".jpg";
					Resource imageResource = resourceLoader
							.getResource(com.hoperun.framework.util.StringUtils
									.cleanPath(path + File.separator + name));
					FileOutputStream fops = new FileOutputStream(
							imageResource.getFile());
					saveFile(imageBase64, fops);
					LOGGER.debug(" save path is path " + path + File.separator
							+ name);
					list.add(getHttpPathPrefix() + "/" + workerOrderPath + "/"
							+ owner + "/" + name);
				}
			}

			return list;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return list;
		} catch (IOException e) {
			e.printStackTrace();
			return list;
		} catch (Exception e) {
			e.printStackTrace();
			return list;
		}
	}

	@Override
	public FileInfo uploadApkRealPath(MultipartFile mFile) {

		FileInfo fileInfo = null;

		try {

			String path = getUploadPath() + File.separator + downloadPath;
			String http = getHttpPathPrefix() + "/" + getDownloadPath();

			Resource resource = resourceLoader.getResource(StringUtils
					.cleanPath(path));
			if (!resource.exists()) {
				FileUtils.forceMkdir(resource.getFile());
			}

			if (!mFile.isEmpty()) {
				String originFileName = mFile.getOriginalFilename();
				long fileSize = mFile.getSize();
				String suffix = originFileName.split("\\.")[originFileName
						.split("\\.").length - 1];
				String fileName = (new Date()).getTime() + "." + suffix;
				String filePath = path + File.separator + fileName;

				Resource fileResource = resourceLoader.getResource(StringUtils
						.cleanPath(filePath));

				CommonFile cf = new CommonFile(mFile.getInputStream());

				cf.save(fileResource.getFile());

				fileInfo = new FileInfo();
				fileInfo.setHttpPath(http + "/" + fileName);
				fileInfo.setSuffix(suffix);
				fileInfo.setSize(fileSize);
				fileInfo.setFileName(fileName) ;
				
				return fileInfo;
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return fileInfo;
	}

	@Override
	public List<FileInfo> uploadWorkOrderRealPath(String owner,
			String transferId, List<MultipartFile> mFiles) {
		List<FileInfo> list = Lists.newArrayList();

		try {

			String path = getUploadPath() + File.separator + workerOrderPath;
			String http = getHttpPathPrefix() + "/" + workerOrderPath;

			if (!StringUtils.isEmpty(owner)) {
				path += File.separator + owner;
				http += "/" + owner;
			}
			if (!StringUtils.isEmpty(transferId)) {
				path += File.separator + transferId;
				http += "/" + transferId;
			}
			Resource resource = resourceLoader.getResource(StringUtils
					.cleanPath(path));
			if (!resource.exists()) {
				FileUtils.forceMkdir(resource.getFile());
			}

			for (MultipartFile mFile : mFiles) {
				if (!mFile.isEmpty()) {
					String originFileName = mFile.getOriginalFilename();
					String contentType = mFile.getContentType();
					long fileSize = mFile.getSize();
					String suffix = originFileName.split("\\.")[originFileName
							.split("\\.").length - 1];
					String fileName = (new Date()).getTime() + "." + suffix;
					String filePath = path + File.separator + fileName;

					Resource fileResource = resourceLoader
							.getResource(StringUtils.cleanPath(filePath));

					CommonFile cf = new CommonFile(mFile.getInputStream());

					if ("image/jpeg".equalsIgnoreCase(contentType)
							|| "image/x-png".equalsIgnoreCase(contentType)
							|| "image/png".equalsIgnoreCase(contentType)
							|| "image/gif".equalsIgnoreCase(contentType)) {
						CommonImage commonImage = new CommonImage(
								mFile.getInputStream());
						String shortFilePath = filePath.replace("." + suffix,
								"-z-0" + "." + suffix);
						Resource shortFileResource = resourceLoader
								.getResource(StringUtils
										.cleanPath(shortFilePath));
						commonImage.cropWithContainer(50, 50).save(
								shortFileResource.getFile());

					}

					cf.save(fileResource.getFile());

					FileInfo fileInfo = new FileInfo();
					fileInfo.setContentType(contentType);
					fileInfo.setHttpPath(http + "/" + fileName);
					fileInfo.setSuffix(suffix);
					fileInfo.setSize(fileSize);

					list.add(fileInfo);
				}
			}

			return list;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return list;
		} catch (IOException e) {
			e.printStackTrace();
			return list;
		} catch (Exception e) {
			e.printStackTrace();
			return list;
		}
	}

	@Override
	public Resource getDowloadRealFile(String path) {
		return resourceLoader.getResource(StringUtils.cleanPath(getUploadPath()
				+ File.separator + downloadPath + File.separator + path));
	}

	public void setUploadPath(String uploadPath) {
		this.uploadPath = uploadPath;
	}

	@Override
	public String getHttpPathPrefix() {
		return "/file";
	}

	private void initStaticResourceHandlerMapping() {
		Map<String, HttpRequestHandler> urlMap = new LinkedHashMap<String, HttpRequestHandler>();
		ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();

		requestHandler
				.setLocations(Collections.singletonList(resourceLoader
						.getResource(StringUtils.cleanPath(uploadPath)
								+ File.separator)));
		requestHandler.setCacheSeconds(cacheSeconds);
		requestHandler.setServletContext(servletContext);
		requestHandler.setApplicationContext(applicationContext);
		urlMap.put(getHttpPathPrefix() + "/**", requestHandler);

		SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
		handlerMapping.setUrlMap(urlMap);
		applicationContext.getAutowireCapableBeanFactory().initializeBean(
				handlerMapping, null);
		ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
		DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext
				.getBeanFactory();
		defaultListableBeanFactory.registerSingleton(
				"fileResourceHandlerMapping", handlerMapping);

		// refresh context
		applicationContext.publishEvent(new ContextRefreshedEvent(
				applicationContext));
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		initStaticResourceHandlerMapping();
	}

	@Override
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
	}

	@Override
	public Resource getRealPathByBizAndOwner(String biz, String owner) {
		String path = StringUtils.cleanPath(getUploadPath()
				+ File.separator
				+ biz
				+ com.hoperun.framework.util.StringUtils.devidePath(owner,
						File.separator));
		Resource resource = resourceLoader.getResource(path);
		try {
			if (!resource.exists()) {
				FileUtils.forceMkdir(resource.getFile());
			}
			return resource;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public String getHttpPathByBizAndOwner(String biz, String owner) {
		return getHttpPathPrefix()
				+ "/"
				+ biz
				+ com.hoperun.framework.util.StringUtils
						.devidePath(owner, "/");
	}

	public static void main(String[] args) {
		String owner = "123456";
		int len = owner.length();
		int start = 0;
		StringBuffer sb = new StringBuffer();
		int step = 2;
		while (start < len) {
			if (len - start < step) {
				step = len - start;
			}
			sb.append("/" + owner.substring(start, start + step));
			start += 2;
		}
		System.out.println(sb.toString());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.sklay.core.io.StaticResourceMappingManager#getResourceByPath(java
	 * .lang.String)
	 */
	@Override
	public Resource getResourceByPath(String path) {
		return resourceLoader.getResource(StringUtils.cleanPath(getUploadPath()
				+ path.replaceFirst(getHttpPathPrefix(), "")));
	}

	public String getDownloadPath() {
		return downloadPath;
	}

	public void setDownloadPath(String downloadPath) {
		this.downloadPath = downloadPath;
	}

	public String getWorkerOrderPath() {
		return workerOrderPath;
	}

	public void setWorkerOrderPath(String workerOrderPath) {
		this.workerOrderPath = workerOrderPath;
	}

	/**
	 * 从加密的data数据中保存文件
	 * 
	 * @version: v1.0.0
	 * @author: mengbin
	 * @param data
	 *             :
	 *            ...
	 * @date: 2013-11-23上午11:51:15
	 */
	private static void saveFile(String data, OutputStream os) throws Exception {
		String[] tmps = data.split(",");
		String content = tmps[1]; // 数据区

		String[] tmps1 = tmps[0].split(";");
		String encodeType = tmps1[1]; // 编码方式

		byte[] buf = null;
		if ("base64".equalsIgnoreCase(encodeType)) {
			BASE64Decoder decoder = new BASE64Decoder();
			buf = decoder.decodeBuffer(content);
		}
		os.write(buf);
		os.flush();
		os.close();
	}
}
